import wx
from Constant import *
from PublicMethod import *
'''
Basic_MovingCreature :

   The moving object, it can move to left, right, up and down four aspect if there is some area that is

   not an obstacle for this object.However, if this moving object encounter the object belong to those
   
   in table - LIST_CONTACT_BURST for this, this moving object is bursting.
'''
class Basic_MovingCreature():
    '''
    Constructor - Basic_MovingCreature
        mainMap - object pointer - MainMap
        pos - current position of this in map (row, column)
        objType - object type of this
    '''
    def __init__(self, mainMap, pos, objType):
        self._001_initialInstanceVariable(mainMap, pos, objType)
        self._002_bindAction()
        self.ACT001_startTimer()
    '''
    function _001 : initialize the variables used for this object
        mainMap : object pointer - MainMap
        pos - current position of this object in map (row, column)
        objType - object type of this
    '''
    def _001_initialInstanceVariable(self, mainMap, pos, objType):
        #object pointer - MainMap
        self.mainMap = mainMap
        #record current position in map (row, column)
        self.posInMap = pos
        #record object type
        self.objType = objType
        #timer of moving of creature
        self.timer_move = wx.Timer()
        #timer of judge bursting
        self.timer_judgeBurst = wx.Timer()
        #the before position
        self.posBefore = None
        #the index of current image
        self.curImageIndex = 0
        
        self.listHasGo = []
    '''
    function _002 : bind object event to specific method
    '''
    def _002_bindAction(self):
        #bind destroy action to mainMap object
        self.mainMap.evtCollector.Bind(EVT_DESTROY_GAME_OBJ, self.SLOT001_destroy)
        #bind moving action to timer
        self.timer_move.Bind(wx.EVT_TIMER, self.SLOT002_moveToNextPosition)
        #bind burst-judging to timer
        self.timer_judgeBurst.Bind(wx.EVT_TIMER, self.SLOT003_judgeBursting)
    '''
    function _003 : destroy all object used for this class
    '''
    def _003_destroyAllObject(self):
        self.timer_move.Stop()
        self.timer_move.Destroy()
        self.timer_judgeBurst.Stop()
        self.timer_judgeBurst.Destroy()
        del self
    '''
    function _004 : judge and get the next moving position
    '''
    def _004_judgeAndGetNextMoving(self):
        dir = [[self.posInMap[0],self.posInMap[1] + 1], [self.posInMap[0],self.posInMap[1] - 1], 
               [self.posInMap[0] + 1,self.posInMap[1]], [self.posInMap[0] - 1,self.posInMap[1]]]
        index = 0
        #delete illegal and obstacle position
        while index < dir.__len__() :
            if self.mainMap.ACT004_judgePosIsOutOfRange(dir[index]) :  
                dir.__delitem__(index)
            elif LIST_IS_OBSTACLE[str(self.objType)][self.mainMap.GET001_objTypeIn_listCube(dir[index])] :
                dir.__delitem__(index)
            else :
                index = index + 1
        '''
        #do not go back as soon as possible
        if dir.__len__() > 1 and self.posBefore != None:
            index = 0
            while index < dir.__len__() :
                if self.posBefore[0] == dir[index][0] and self.posBefore[1] == dir[index][1] :
                    dir.__delitem__(index)
                    break
                index = index + 1
        #choose next position
        if dir.__len__() > 0 :
            getIndex = PublicMethod.ACT003_getRandomNum(0, dir.__len__() - 1)
            return dir[getIndex]
        else :
            return self.posInMap
        '''
        if dir.__len__() == 0 :
            return self.posInMap
        elif dir.__len__() == 1 :
            return dir[0]
        else :
            list_priority = []
            index = 0
            while index < dir.__len__() :
                getPro = self.ACT002_getMovePosPriority(self.posInMap, dir[index], self.posBefore, self.listHasGo)
                list_priority.append(getPro)
                index = index + 1
            #get maximum priority of next position index in list - list_priority
            index = 1
            maxPr = list_priority[0]
            chooseIndex = 0
            while index < list_priority.__len__() :
                if list_priority[index] > maxPr :
                    maxPr = list_priority[index]
                    chooseIndex = index
                index = index + 1
            #check adding position to list
            index = 0
            checkNum = 0
            while index < list_priority.__len__() :
                if list_priority[index] >= 4 :
                    checkNum = checkNum + 1
                index = index + 1
            if checkNum > 1 :
                self.ACT007_addGoPosToList(self.posInMap, dir[chooseIndex], self.listHasGo)
                if self.posBefore != None :
                    self.ACT007_addGoPosToList(self.posInMap, self.posBefore, self.listHasGo)
            return dir[chooseIndex]
    '''
    function ACT001 : start timer used for this class
    '''
    def ACT001_startTimer(self):
        self.timer_move.Start(1000)
        self.timer_judgeBurst.Start(200)
    '''
    function ACT002 : get the moving priority of position - posNext
    '''
    def ACT002_getMovePosPriority(self, posCur, posNext, posBefore, listHasGo):
        priority = None
        isNextPos8AspectNoObt = self.ACT003_getPosIs8AspectNoObstacle(posNext, posCur)
        isNextPos4AspectNoObt = self.ACT006_getPosIs4AspectNoObstacle(posNext, posCur)
        isSameAspAsCur = self.ACT004_getSameAspectAsCurGo(posCur, posNext, posBefore)
        #priority None : the next position os obstacle or does not exist
        if (self.mainMap.ACT004_judgePosIsOutOfRange(posNext)) | \
           (LIST_IS_OBSTACLE[str(self.objType)][self.mainMap.GET001_objTypeIn_listCube(posNext)]):
            pass
        #priority 1 : the next position that player goes is before one step
        elif (posBefore != None) and (posNext[0] == posBefore[0]) and (posNext[1] == posBefore[1]) :
            priority = 1
        #priority 2 : the next position is all no obstacle in 8 direction but the aspect is not the same as 
        #             aspect that player goes
        elif isNextPos8AspectNoObt and (not isSameAspAsCur) :
            priority = 2
        #priority 3 : the next position is all no obstacle in 8 direction and the aspect is the same as 
        #             aspect that player goes
        elif isNextPos8AspectNoObt and isSameAspAsCur :
            priority = 3
        #priority 4 : player has been the next position
        elif self.ACT005_getNextPosIsEverGone(posCur, posNext, listHasGo) :
            priority = 4
        #priority 5 : the next position is all no obstacle in 4 direction, but another 4 direction has some obstacle
        elif isNextPos4AspectNoObt and (not isNextPos8AspectNoObt) :
            priority = 5
        #priority 6 : the next position exists some obstacle in 4 direction, the aspect is not the same as 
        #             aspect that player goes
        elif (not isNextPos4AspectNoObt) and (not isSameAspAsCur) :
            priority = 6
        #priority 7 : the next position exists some obstacle in 4 direction, the aspect is the same as 
        #             aspect that player goes
        elif (not isNextPos4AspectNoObt) and (isSameAspAsCur) :
            priority = 7
        return priority
    '''
    function ACT003 : judge whether there is no obstacle around 8 aspects of position - posNext
    '''
    def ACT003_getPosIs8AspectNoObstacle(self, posNext, posCur):
        dir = [[posNext[0] - 1, posNext[1] - 1], [posNext[0] - 1, posNext[1]], [posNext[0] - 1, posNext[1] + 1],
               [posNext[0], posNext[1] - 1], [posNext[0], posNext[1] + 1],
               [posNext[0] + 1, posNext[1] - 1], [posNext[0] + 1, posNext[1]], [posNext[0] + 1, posNext[1] + 1]]
        isAllNoObl = True
        index = 0
        while isAllNoObl and index < dir.__len__() :
            NextPosObjType = self.mainMap.GET001_objTypeIn_listCube(dir[index])
            if self.mainMap.ACT004_judgePosIsOutOfRange(dir[index]) : #the position is illegal
                isAllNoObl = False
            elif (not(posCur[0] == dir[0] and posCur[1] == dir[1])) and \
                 (LIST_IS_OBSTACLE[str(self.objType)][NextPosObjType]) :
                isAllNoObl = False
            index = index + 1
        return isAllNoObl
    '''
    function ACT004 : judge whether the next direction is same as before direction
    '''
    def ACT004_getSameAspectAsCurGo(self, posCur, posNext, posBefore):
        isSame = False
        if posBefore != None :
            if ((posCur[0] - posBefore[0]) == (posNext[0] - posCur[0])) and \
               ((posCur[1] - posBefore[1]) == (posNext[1] - posCur[1]))  :
                isSame = True
        return isSame
    '''
    function ACT005 : judge whether the position - posNext has ever gone
    '''
    def ACT005_getNextPosIsEverGone(self, posCur, posNext, list):
        isGo = False
        isFound = False
        base = 2
        index = 0
        while (not isFound) and (index < list.__len__()) :
            if (list[index][0] == posCur[0]) and (list[index][1] == posCur[1]) :
                dir = self.ACT008_getDirection(posNext, posCur)
                if (dir != None) and (list[index][base + dir] == POS_EVER_GO):
                    isGo = True
                elif list[index][base + dir] == POS_OBSTACLE : #judge original is obstacle but current is not
                    if not LIST_IS_OBSTACLE[str(self.objType)][self.mainMap.GET001_objTypeIn_listCube(posNext)] :
                        list[index][base + dir] == POS_NOT_GO
                isFound = True
            index = index + 1
        return isGo
    '''
    function ACT006 : judge whether there is no obstacle around 4 aspects of position - posNext
    '''
    def ACT006_getPosIs4AspectNoObstacle(self, posNext, posCur):
        dir = [[posNext[0] - 1, posNext[1]], [posNext[0], posNext[1] - 1], [posNext[0], posNext[1] + 1],
               [posNext[0] + 1, posNext[1]]]
        isAllNoObl = True
        index = 0
        while isAllNoObl and index < dir.__len__() :
            NextPosObjType = self.mainMap.GET001_objTypeIn_listCube(dir[index])
            if self.mainMap.ACT004_judgePosIsOutOfRange(dir[index]) :  #the position is illegal
                isAllNoObl = False
            elif (not(posCur[0] == dir[0] and posCur[1] == dir[1])) and \
                 (LIST_IS_OBSTACLE[str(self.objType)][NextPosObjType]) :
                isAllNoObl = False
            index = index + 1
        return isAllNoObl
    '''
    function ACT007 : add go position record to list of recording all position in 4 aspects has ever gone
    '''
    def ACT007_addGoPosToList(self, posCur, posNext, list):
        index = 0
        isExist = False
        base = 2
        dir = self.ACT008_getDirection(posNext, posCur)
        while (not isExist) and (index < list.__len__()) :
            if (list[index][0] == posCur[0]) and (list[index][1] == posCur[1]) : #the position - posCur has been recorded
                isExist = True
                if dir != None :
                    list[index][base + dir] = POS_EVER_GO
                #check whether deleting this data in index
                indexCol = base
                isDel = True
                while isDel and indexCol < base + 4 :
                    if list[index][indexCol] == POS_NOT_GO :
                        isDel = False
                    indexCol = indexCol + 1
                if isDel :
                    list.__delitem__(index)
                    isExist = False
            index = index + 1
        if not isExist :  #the position - posCur does not exist
            addEle = [posCur[0], posCur[1], -1, -1, -1, -1]
            listPos = [[posCur[0] - 1, posCur[1]], [posCur[0] + 1, posCur[1]], [posCur[0], posCur[1] - 1],
                       [posCur[0], posCur[1] + 1]]
            index = 0
            while index < listPos.__len__() :
                if posNext[0] == listPos[0] and posNext[1] == listPos[1] :
                    addEle[base + index] = POS_EVER_GO
                elif self.posBefore != None and self.posBefore[0] == listPos[0] and self.posBefore[1] == listPos[1] :
                    addEle[base + index] = POS_EVER_GO
                elif LIST_IS_OBSTACLE[str(self.objType)][self.mainMap.GET001_objTypeIn_listCube(listPos[index])] :
                    addEle[base + index] = POS_OBSTACLE
                else :
                    addEle[base + index] = POS_NOT_GO
                index = index + 1
            list.append(addEle)
    '''
    function ACT008 : get direction from position - posCur to posNext
    '''
    def ACT008_getDirection(self, posNext, posCur):
        vector = [0, 0]
        vector[0] = posNext[0] - posCur[0]
        vector[1] = posNext[1] - posCur[1]
        dir = None
        if vector[0] == -1 and vector[1] == 0 : 
            dir = ASP_UP
        elif vector[0] == 1 and vector[1] == 0 : 
            dir = ASP_DOWN
        elif vector[0] == 0 and vector[1] == -1 : 
            dir = ASP_LEFT
        elif vector[0] == 0 and vector[1] == 1 : 
            dir = ASP_RIGHT
        return dir
    '''
    function SLOT001 : slot of destroying this object
    '''
    def SLOT001_destroy(self, event):
        if not event.isClearAll :
            if event.delObjType == self.objType and self.posInMap[0] == event.delPos[0] and \
            self.posInMap[1] == event.delPos[1] :
                self._003_destroyAllObject()
        else :
            self._003_destroyAllObject()
        event.Skip()
    '''
    function SLOT002 : slot of moving to next position and change next image of this
    '''
    def SLOT002_moveToNextPosition(self, event):
        nextPos = self._004_judgeAndGetNextMoving()
        self.curImageIndex = (self.curImageIndex + 1) % LIST_FILENAME_GAMEOBJECT[self.objType].__len__()
        self.mainMap.ACT002_MoveObj(self.posInMap, nextPos, self.curImageIndex)
        self.posBefore = self.posInMap
        self.posInMap = nextPos
    '''
    function SLOT003 : slot of judging whether this encounters the object that makes itself burst
    '''
    def SLOT003_judgeBursting(self, event):
        dir = [[0,1], [0,-1], [1,0], [-1,0]]
        index = 0
        isBurst = False
        while (not isBurst) and (index < dir.__len__()) :
            newPos = (self.posInMap[0] + dir[index][0], self.posInMap[1] + dir[index][1])
            newObjType = self.mainMap.GET001_objTypeIn_listCube(newPos)
            if LIST_CONTACT_BURST[str(self.objType)].__contains__(newObjType) : #encounter the bursting object
                isBurst = True
            index = index + 1
        if isBurst :  #burst itself
            self.mainMap.ACT005_bursting(self.objType, self.posInMap)
            self._003_destroyAllObject()